#include "sys.h"
#include "net.h"
#include "log.h"
#include "us_ctl.h"
#include "uentry.h"
#include "thread_pool.h"
#define THREAD_COUNT_MAX 10
void us_svr_run(uint16_t ctl_port)
{
    int ret, ctl_fd;
    char ctl_buf[UCTL_BUFFER_MAX] = { 0 }, snd_buf[UCTL_BUFFER_MAX] = {0};
    fd_set rdfds;
    struct timeval tmo;
    struct sockaddr_in ctl_addr, peer_addr;
    socklen_t peer_addr_len;
    uctl_conf_t uconf;
    uentry_t* ue;
    thread_pool_t *tpool;

    tpool = thread_pool_new(1);
    thread_pool_set_auto_extern(tpool);
    thread_pool_set_limit_number(tpool, THREAD_COUNT_MAX);

    ctl_fd = socket_dgram_new();

    sockaddr_set(&ctl_addr, AF_INET, htons(ctl_port), "0.0.0.0");
    if (0 > bind(ctl_fd, (struct sockaddr*)&ctl_addr, sizeof(ctl_addr))) {
        log_syserr("ctl bind error.");
        return;
    }

    while (1) {
        bzero(ctl_buf, sizeof(ctl_buf));
        bzero(snd_buf, sizeof(snd_buf));
        FD_ZERO(&rdfds);
        FD_SET(ctl_fd, &rdfds);
        tmo.tv_sec = 1;
        tmo.tv_usec = 0;
        ret = select(ctl_fd + 1, &rdfds, NULL, NULL, &tmo);
        if (FD_ISSET(ctl_fd, &rdfds)) {
            if ((ue = uentry_new())) {
                peer_addr_len = sizeof(ue->peer_addr);
                ret = recvfrom(ctl_fd, ctl_buf, sizeof(ctl_buf), 0, (struct sockaddr*)&peer_addr, &peer_addr_len);
                if (ret > 0) {
                    log_trace("Main Ctl rcv peer %s:%d", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
                    log_trace("Main Ctl rcv ctl conf:%s", ctl_buf);
                    if(uentry_bind(ue)){
                        log_trace("UEntry bind to port %d", ntohs(ue->local_addr.sin_port));
                        uctl_conf_str2struct(&uconf, ctl_buf, ret);
                        if(strcmp(uconf.cmd, UCTL_CONF_CMD_REQ) == 0){
                            bzero(&uconf, sizeof(uconf));
                            strcpy(uconf.cmd, UCTL_CONF_CMD_REDIRECT);
                            uconf.port = ntohs(ue->local_addr.sin_port);
                            uctl_conf_struct2str(&uconf, snd_buf, sizeof(snd_buf));
                            ret = sendto(ctl_fd, snd_buf, strlen(snd_buf), 0, (struct sockaddr*)&peer_addr, sizeof(peer_addr));
                            if(ret > 0){
                                thread_pool_add_task(tpool, uentry_run, (void*)ue);
                            }
                        }
                    }
                }
            }
        }
    }
}
